#include <errno.h>
#include <sys/epoll.h>
#include "appnet_event.h"
typedef struct aeApiState
{
	int epfd;
	struct epoll_event *events;
} aeApiState;
static int aeApiCreate( aeEventLoop *eventLoop )
{
	aeApiState *state = zmalloc( sizeof(aeApiState) );
	if (!state)
	{
		return -1;
	}
	state->events = zmalloc( sizeof(struct epoll_event) * eventLoop->setsize );
	if (!state->events)
	{
		zfree( state );
		return -1;
	}
	state->epfd = epoll_create( 1024 ); /* 1024 is just a hint for the kernel */
	if (state->epfd == -1)
	{
		zfree( state->events );
		zfree( state );
		return -1;
	}
	eventLoop->apidata = state;
	return 0;
}
static int aeApiResize( aeEventLoop *eventLoop , int setsize )
{
	aeApiState *state = eventLoop->apidata;
	state->events = zrealloc( state->events , sizeof(struct epoll_event) * setsize );
	return 0;
}
static void aeApiFree( aeEventLoop *eventLoop )
{
	aeApiState *state = eventLoop->apidata;
	close( state->epfd );
	zfree( state->events );
	zfree( state );
}
static int aeApiAddEvent( aeEventLoop *eventLoop , int fd , int mask )
{
	aeApiState *state = eventLoop->apidata;
	struct epoll_event ee;
	
	int a = eventLoop->events[fd].mask;
	/* If the fd was already monitored for some event, we need a MOD
	 * operation. Otherwise we need an ADD operation. */
	int op = ( eventLoop->events[fd].mask == AE_NONE ) ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
	
	ee.events = 0;
	mask |= eventLoop->events[fd].mask; /* Merge old events */
	
	if (mask & AE_READABLE)
	{
		ee.events |= EPOLLIN;
	}
	if (mask & AE_WRITABLE)
	{
		ee.events |= EPOLLOUT;
	}
	ee.data.u64 = 0; /* avoid valgrind warning */
	ee.data.fd = fd;
	if (epoll_ctl( state->epfd , op , fd , &ee ) == -1)
	{
		printf( "[epoll_ctr1111 error epfd=%d,op=%d,fd=%d,errno=%d,error=%s]\n" , state->epfd , op , fd , errno , strerror( errno ) );
		return -1;
	}
	return 0;
}
static void aeApiDelEvent( aeEventLoop *eventLoop , int fd , int delmask )
{
	aeApiState *state = eventLoop->apidata;
	struct epoll_event ee;
	int mask = eventLoop->events[fd].mask & ( ~delmask );
	ee.events = 0;
	if (mask & AE_READABLE)
	{
		ee.events |= EPOLLIN;
	}
	if (mask & AE_WRITABLE)
	{
		ee.events |= EPOLLOUT;
	}
	ee.data.u64 = 0; /* avoid valgrind warning */
	ee.data.fd = fd;
	if (mask != AE_NONE)
	{
		epoll_ctl( state->epfd , EPOLL_CTL_MOD , fd , &ee );
	}
	else
	{
		/* Note, Kernel < 2.6.9 requires a non null event pointer even for
		 * EPOLL_CTL_DEL. */
		epoll_ctl( state->epfd , EPOLL_CTL_DEL , fd , &ee );
	}
}
static int aeApiPoll( aeEventLoop *eventLoop , struct timeval *tvp )
{
	aeApiState *state = eventLoop->apidata;
	int retval,numevents = 0;
	retval = epoll_wait( state->epfd , state->events , eventLoop->setsize ,
			tvp ? ( tvp->tv_sec * 1000 + tvp->tv_usec / 1000 ) : -1 );
	if (retval > 0)
	{
		int j;
		numevents = retval;
		for (j = 0; j < numevents; j++)
		{
			int mask = 0;
			struct epoll_event *e = state->events + j;
			if (e->events & EPOLLIN)
			{
				mask |= AE_READABLE;
			}
			if (e->events & EPOLLOUT)
			{
				mask |= AE_WRITABLE;
			}
			if (e->events & EPOLLERR)
			{
				mask |= AE_WRITABLE;
			}
			if (e->events & EPOLLHUP)
			{
				mask |= AE_WRITABLE;
			}
			//将触发的事件fd和类型，加入到，触发的事件列表中,这样做是为上层提供统一的激活事件列表。如果仅考虑linux平台，可以直接在里面处理�?
			eventLoop->fired[j].fd = e->data.fd;
			eventLoop->fired[j].mask = mask;
		}
	}
	return numevents;
}
static char *aeApiName( void )
{
	return "epoll";
}
